import java.io.FileWriter;
import java.io.PrintWriter;

/**
* Esta clase representa una partida del mus con sus diferentes metodos
* 
* @author Juan Belmonte, Carmen Parra, Luis Rodriguez
* @version 0.5.0
*/
public class Partida {
	private Vaca [] vacasPartida;
	private Baraja barajaPartida;
	public Carta[] barajaDescartes =null;
	private Pareja pareja1;
	private Pareja pareja2;
	private Sena[] senas;
	private JuegoCartas juego;
	private Carta[] cartasMesa  = null;
	private String [] ganadoresApuestasMano;
	
	//booleano que usaré para contar cartas y un contador para lo mismo
	private boolean finConteo;
	int [] cont;
	
	/**
	* Constructor por copia de la clase Partida
	* 
	* @param juego JuegoCartas que indica el tipo de juego respecto al cual se crea una partida nueva
	* 
	*/
	public Partida(JuegoCartas juego, Jugador[] jugadores){
	
		vacasPartida = new Vaca[1]; //minimo se jugar�n 2 vacas;
		senas=new Sena[juego.getSenas().length -1];
		senas=juego.getSenas();
		barajaPartida = new Baraja(juego);
		cartasMesa = new Carta[16];
		this.introducirJugadoresPartida(jugadores);		
		finConteo = false;
		cont = new int[4];
		ganadoresApuestasMano = new String[4];
		
	}
	
	
	
	public Sena[] getSenas() {
		return senas;
	}


	public String[] getGanadoresApuestasMano() {
		return ganadoresApuestasMano;
	}



	public Baraja getBarajaPartida(){
		return this.barajaPartida;
	}
	
	public void setBarajaPartida(Baraja barajaPartida) {
		this.barajaPartida = barajaPartida;
	}

	public Carta[] getBarajaDescartes(){
		return this.barajaDescartes;
	}
	
	public void setBarajaDescartes(Carta[] nuevaBarajaDescartes){
		this.barajaDescartes = nuevaBarajaDescartes;
	}
	public Carta[] getCartasMesa(){
		return this.cartasMesa;
	}
	
	public JuegoCartas getJuegoCartas(){
		return this.juego;
	}
	
	/**
	* Metodo que devuelve el numero del jugador segun un turno y mano de juego
	* 
	* @param turno entero que indica dentro del orden de juego el turno
	* @param manoJuego entero que indica quien es mano
	* 
	*/
	public int devolverNumJug(int turno, int manoJuego){
		int aux, cont=0;
		if(manoJuego==0){
			return turno;
		}else{
			aux = manoJuego + turno + 1;
			do{
				if(cont==3){
					cont=0;
					aux--;
				}else{
					cont++;
					aux--;
				}
			}while(aux>0);
		}
		return cont;
	}
	
	/**
	* Metodo que inserta una carta nueva en una posicion del array de cartas de la mesa
	* 
	* @param carta Carta que es la carta a insertar
	* @param pos entero que es la posición donde se inserta la carta
	* 
	*/
	public void insertarCartaMesa(Carta carta, int pos){
		this.cartasMesa[pos] = carta;
	}
	
	/**
	* Metodo que inicializa las parejas del juego
	* 
	* @param jugadores Jugador[] que pasa por cabecera los 4 jugadores de la partida
	* 
	*/
	public void introducirJugadoresPartida(Jugador[] jugadores){
		pareja1 = new Pareja(jugadores[0],jugadores[2]);
		pareja2 = new Pareja(jugadores[1],jugadores[3]);
	}
	
	/**
	* Metodo que devuelve el jugador que es mano 
	* 
	*/
	public Jugador getJugadorMano(){
		int i=0;
		boolean parar = false;
		while(i < this.getJugadores().length && !parar){
			if(this.getJugadores()[i].getMano() == true){
				parar=true;
			}else{
				i++;
			}
		}
		return this.getJugadores()[i];
	}
	
	/**
	* Metodo que saca los nombres de los jugadores de la partida 
	* 
	*/
	public Jugador[] getJugadores(){
		Jugador[] jugadores = new Jugador[4];
		jugadores[0] = this.getPareja(1).getJugador(1);
		jugadores[1] = this.getPareja(2).getJugador(1);
		jugadores[2] = this.getPareja(1).getJugador(2);
		jugadores[3] = this.getPareja(2).getJugador(2);
		return jugadores;
	}
	
	/**
	* Metodo simple que devuelve la pareja segun el numero que se le pasa
	* 
	* @param n entero que indica que pareja se devuelve
	* 
	*/
	public Pareja getPareja (int n){
		if(n==1){
			return pareja1;
		}else{
			return pareja2;
		}
	}
	
	
	/**
	* Metodo que redimensiona el array de descartes, elimina una carta segun una posicion dada
	* 
	* @param pos entero que le indica la carta a eliminar
	* 
	*/
	public void redimensionarBarajaDescartes(int pos){
		if (pos<this.barajaDescartes.length){
			Carta [] barajaAux = new Carta [this.barajaDescartes.length -1];
			int i, j;
			for(i =0, j =0; i<this.barajaDescartes.length ; i ++, j++){
				if(i!=pos){
					barajaAux[j]=this.barajaDescartes[i];
				}else{
					j--;
				}
			}
			this.barajaDescartes=barajaAux;
		}
	}
	
	
	/**
	* Metodo que reparte las cartas de la baraja entre los 4 jugadores
	*  
	*/
	public void repartir(){
		int cont=0;
		for(int i=0; i<=3; i++){
			for(int j=0; j<=3; j++){
				if(j==0 || j==2){
					if(j==0){
						cartasMesa[cont] = this.barajaPartida.getCarta(0);
						barajaPartida.redimensionarBaraja(0);
						cont++;
					}else{
						cartasMesa[cont] = this.barajaPartida.getCarta(0);
						barajaPartida.redimensionarBaraja(0);
						cont++;
					}
				}else{
					if(j==1){
						cartasMesa[cont] = this.barajaPartida.getCarta(0);
						barajaPartida.redimensionarBaraja(0);
						cont++;
					}else{
						cartasMesa[cont] = this.barajaPartida.getCarta(0);
						barajaPartida.redimensionarBaraja(0);
						cont++;
					}
				}
			}
		}
	
		
		for (int i = 0; i < cartasMesa.length; i++){
			if(i<4){
				getPareja(1).getJugador(1).setCartaJugador(i, cartasMesa[i]);
			}else if(i<8){
				getPareja(2).getJugador(1).setCartaJugador(i - 4, cartasMesa[i]);
			}else if(i<12){
				getPareja(1).getJugador(2).setCartaJugador(i - 8, cartasMesa[i]);
			}else{
				getPareja(2).getJugador(2).setCartaJugador(i - 12, cartasMesa[i]);
			}
		}
	}
	
	/**
	* Metodo que muestras las 4 cartas de cada jugador
	* 
	*/
	public void mostrarCartas (){
		System.out.println(getPareja(1).getJugador(1).getNombre() + " :");
		System.out.println(getPareja(1).getJugador(1).mostrarCartas());
		System.out.println(getPareja(2).getJugador(1).getNombre() + " :");
		System.out.println(getPareja(2).getJugador(1).mostrarCartas());
		System.out.println(getPareja(1).getJugador(2).getNombre() + " :");
		System.out.println(getPareja(1).getJugador(2).mostrarCartas());
		System.out.println(getPareja(2).getJugador(2).getNombre() + " :");
		System.out.println(getPareja(2).getJugador(2).mostrarCartas());
	}

	public Vaca[] getVacasPartida() {
		return vacasPartida;
	}

	public void setVacasPartida(Vaca[] vacasPartida) {
		this.vacasPartida = vacasPartida;
	}
	
	/**
	* Metodo que cuenta los puntos despues de una mano
	* 
	*/
	public void conteo(int manoJuego){
		int mano=this.getVacasPartida()[this.getVacasPartida().length -1].getManosVaca().length - 1;
		for(int i=0; i<4;i++){
			if(i==0){
				ganadoresApuestasMano[i] = ("GRANDE: ");
			}else if(i==1){
				ganadoresApuestasMano[i] = ("CHICA: ");
			}else if(i==2){
				ganadoresApuestasMano[i] = ("PARES: ");
			}else{
				ganadoresApuestasMano[i] = ("JUEGO: ");
			}
			if(!this.getVacasPartida()[this.getVacasPartida().length-1].getManosVaca()[mano].getApuesta(i).apuestaPendiente()){
				//Quiere decir que la apuesta no quedó pendiente, entonces me quedo con la mayor, que será la ganadora
				int apuesta1=this.getVacasPartida()[this.getVacasPartida().length-1].getManosVaca()[mano].getApuesta(i).getValorApuesta(0);
				int apuesta2=this.getVacasPartida()[this.getVacasPartida().length-1].getManosVaca()[mano].getApuesta(i).getValorApuesta(1);
				
				int aux = this.devolverNumJug(0, manoJuego);
				if(aux==0 || aux==2){
					if(apuesta1 > apuesta2){
						//quiere decir que la pareja1 gano a la pareja2 la apusta, luego:
						this.getPareja(1).actualizarEstadisticasPuntosPareja(apuesta1);
						ganadoresApuestasMano[i] = ganadoresApuestasMano[i] + ("pareja1");
					}else if(apuesta2 > apuesta1){
						this.getPareja(2).actualizarEstadisticasPuntosPareja(apuesta2);
						ganadoresApuestasMano[i] = ganadoresApuestasMano[i] + ("pareja2");
					}
						
				}else{
					if(apuesta1 > apuesta2){
						//quiere decir que la pareja2 gano a la pareja1 la apusta, luego:
						this.getPareja(1).actualizarEstadisticasPuntosPareja(apuesta2);
						ganadoresApuestasMano[i] = ganadoresApuestasMano[i] + ("pareja2");
					}else if(apuesta2 > apuesta1){
						this.getPareja(2).actualizarEstadisticasPuntosPareja(apuesta1);
						ganadoresApuestasMano[i] = ganadoresApuestasMano[i] + ("pareja1");
					}
				}
			}else{//Si esta pendiente habría que hacer un método que contase la apuesta según las cartas
				if(i<2){
					int turno=conteoEmpate(i);
					int jug = this.devolverNumJug(turno, manoJuego);
					if(jug==0 || jug==2){
						ganadoresApuestasMano[i] = ganadoresApuestasMano[i] + ("pareja1");
					}else{
						ganadoresApuestasMano[i] = ganadoresApuestasMano[i] + ("pareja2");
					}
				}else{
					//SIN HACER PARA PARES NI JUEGO
					ganadoresApuestasMano[i] = ganadoresApuestasMano[i] + ("Empate");
				}
			}
		}
	}
	
	/**
	* Metodo que cuenta los puntos de las apuestas pendientes según las cartas
	* 
	* @param apuesta entero que indica que apuesta mirar
	* 
	* @return entero que indica la pareja que ganó la apuesta (1 o 2)
	* 
	*/
	public int conteoEmpate(int apuesta){
		int resultado =0;
		switch (apuesta) {
		case 0: resultado=conteoEmpateGrande();
			break;
		case 1: resultado=conteoEmpateChica();
			break;
		case 2: resultado=conteoEmpatePares();
			break;
		case 3: resultado=conteoEmpateJuego();
			break;
		default:
			break;
		}
		
		return resultado;
	}
	
	/**
	* Metodo auxiliar que cuenta los puntos de la apuesta a grande empatada
	* 
	* @return entero que indica el nº jugador que ganó
	* 
	*/
	public int conteoEmpateGrande(){
		

		finConteo = false;
		this.reseteoCont();
		int mano = 0;
		int carta=10;

		
		cont[0] = contarCartas(carta, 0);
		cont[1] = contarCartas(carta, 1);
		cont[2] = contarCartas(carta, 2);
		cont[3] = contarCartas(carta, 3);
		
		mano = mayorArray(cont);
		
		if(mano!=-1){
			return mano;
		}else{
			carta--;
			int lon = 0;
			for(int i=0; i<this.cont.length;i++){
				if(this.cont[i] == -2){
					lon++;
					cont[i] = 1;
				}else{
					cont[i]=0;
				}
			}
			
			
			int [] nuevoArray = new int[lon];
			int n=0;
			for(int i=0; i<this.cont.length;i++){
				if(this.cont[i] == 1){
					nuevoArray[n]=contarCartas(carta, i);
					n++;
				}
			}
			int manoAux;
			int j;
			do{
				j=0;
				manoAux = mayorArray(nuevoArray);
				if(manoAux!=-1){
					for(int i=0; i<this.cont.length;i++){
						if(this.cont[i] ==1 || j==manoAux){
							mano=i;
							return mano;
						}else if(this.cont[i] ==1 || j!=manoAux){
							j++;
						}
					}
					finConteo=true;
				}else{
					carta--;
					lon = 0;
					for(int i=0; i<nuevoArray.length;i++){
						if(nuevoArray[i] == -2){
							lon++;
							nuevoArray[i] = 1;
						}else{
							nuevoArray[i]=0;
						}
					}
					
					
					int [] aux = new int[lon];
					n=0;
					for(int i=0; i<nuevoArray.length;i++){
						if(nuevoArray[i] == 1){
							aux[n]=contarCartas(carta, i);
							n++;
						}
					}
					nuevoArray = aux;
					carta--;
				}
			
			}while(!finConteo || carta>0);
			return mano;
		}
	}
	
	
	/**
	* Metodo auxiliar que cuenta los puntos de la apuesta a chica empatada
	* 
	* @return entero que indica la pareja que ganó la apuesta (1 o 2)
	* 
	*/
	public int conteoEmpateChica(){
		


		finConteo = false;
		this.reseteoCont();
		int mano = 0;
		int carta=1;

		
		cont[0] = contarCartas(carta, 0);
		cont[1] = contarCartas(carta, 1);
		cont[2] = contarCartas(carta, 2);
		cont[3] = contarCartas(carta, 3);
		
		mano = mayorArray(cont);
		
		if(mano!=-1){
			return mano;
		}else{
			carta++;
			int lon = 0;
			for(int i=0; i<this.cont.length;i++){
				if(this.cont[i] == -2){
					lon++;
					cont[i] = 1;
				}else{
					cont[i]=0;
				}
			}
			
			
			int [] nuevoArray = new int[lon];
			int n=0;
			for(int i=0; i<this.cont.length;i++){
				if(this.cont[i] == 1){
					nuevoArray[n]=contarCartas(carta, i);
					n++;
				}
			}
			int manoAux;
			int j;
			do{
				j=0;
				manoAux = mayorArray(nuevoArray);
				if(manoAux!=-1){
					for(int i=0; i<this.cont.length;i++){
						if(this.cont[i] ==1 || j==manoAux){
							mano=i;
							return mano;
						}else if(this.cont[i] ==1 || j!=manoAux){
							j++;
						}
					}
					finConteo=true;
				}else{
					carta--;
					lon = 0;
					for(int i=0; i<nuevoArray.length;i++){
						if(nuevoArray[i] == -2){
							lon++;
							nuevoArray[i] = 1;
						}else{
							nuevoArray[i]=0;
						}
					}
					
					
					int [] aux = new int[lon];
					n=0;
					for(int i=0; i<nuevoArray.length;i++){
						if(nuevoArray[i] == 1){
							aux[n]=contarCartas(carta, i);
							n++;
						}
					}
					nuevoArray = aux;
					carta--;
				}
			
			}while(!finConteo || carta>0);
			return mano;
		}
	}
	
	/**
	* Metodo auxliar que saca el numero de cartas de un jugador y carta dados
	* 
	* @param carta entero que indica la carta a contar
	* @param jugador entero que indica el numero de jugador
	* @return entero que indica el nº de cartas
	* 
	*/
	public int contarCartas(int carta, int jugador){
		
		//me declaro unos contadores
		int cont =0;
		
		for(int i=jugador*4; i<4*jugador + 4;i++){
			if(carta==10){
				if(this.getCartasMesa()[i].getNumero() == 3 || this.getCartasMesa()[i].getNumero() ==10){
					cont++;
				}
			}else if(carta==1){
				if(this.getCartasMesa()[i].getNumero() == 1 || this.getCartasMesa()[i].getNumero() == 2){
					cont++;
				}
			}else{
				if(this.getCartasMesa()[i].getNumero() == carta){
					cont++;
				}
			}
		}
		
		return cont;
	}

	/**
	* Metodo auxiliar que cuenta los puntos de la apuesta a pares empatada
	* 
	* @return entero que indica la pareja que ganó la apuesta (1 o 2)
	* 
	*/
	public int conteoEmpatePares(){
		return 1;
	}
	
	/**
	* Metodo auxiliar que cuenta los puntos de la apuesta a juego empatada
	* 
	* @return entero que indica la pareja que ganó la apuesta (1 o 2)
	* 
	*/
	public int conteoEmpateJuego(){
		return 1;
	}
	
	/**
	* Metodo auxiliar para reiniciar el array contador de partida a 0;
	* 
	*/
	public void reseteoCont(){
		for(int i=0; i<this.cont.length;i++){
			this.cont[i] = 0;
		}
	}
	
	/**
	* Metodo auxiliar que me devuelve el mayor de un array, en el caso de haber empate entre uno
	* o varios me modifica el array contador reinicianzolo a 0 y marcando a -2 las posiciones empatadas
	* 
	* @return entero que devuelve la posicion del array que contiene un numero mayor o -1 si hay empate
	* 
	*/
	public int mayorArray(int [] array){
		int mayor=array[0];
		int pos = 0;
		for(int i=1; i<array.length;i++){
			if(array[i] > mayor){
				mayor=array[i];
				pos=i;
			}else if(array[i] == mayor){
				array[i] = -2;
				array[pos] = -2;
			}
		}
		if(array[pos] != 0){
			return pos;
		}else{
			return -1;
		}
	}
		
	/**
	* Metodo que guarda los datos de una partida pausada
	* 
	* @param manoJuego entero que indica quien es mano
	* @param turno entero que indica dentro del orden de juego el turno
	* @param seJuega String que indica en que estado de la partida se guarda.
	* 
	*/
	public void guardarDatosPartidaPausa(int manoJuego, int turno, String seJuega){
		 try{
			 FileWriter fich = new FileWriter("bin/fichero.txt");
	         PrintWriter pw = new PrintWriter(fich);
	         
	         //Lo primero para guardar los datos es guardar los nombres de los jugadores, en el mismo orden
	         pw.println("JUGADORES");
	         for (int i = 0; i < this.getJugadores().length; i++){
	        	 pw.println(this.getJugadores()[i].getNombre());
	         }
	         
	         //La vaca, la mano de la vaca, el turno de juego, mano de juego y momento de la partida
	         pw.println("\n" + "VACA: " + (this.getVacasPartida().length - 1));
	         pw.println("MANO DE LA VACA: " + (this.getVacasPartida()[this.getVacasPartida().length-1].getManosVaca().length - 1));
	         pw.println("TURNO: " + this.getJugadores()[turno].getNombre());
	         pw.println("\n" + "ES MANO: " + this.getJugadores()[manoJuego].getNombre());
	         pw.println("ESTADO DE LA MANO: " + seJuega);
	         
	         //Lo siguiente la baraja y las cartas de la mesa
	         pw.println("\n" + "BARAJA");
	         for(int i=0;i<this.getBarajaPartida().longitud();i++){
	        	 pw.println(this.getBarajaPartida().getCarta(i).toString());
	         }
	         
	         pw.println("\n" + "CARTAS MESA");
	         for(int i=0; i<this.getCartasMesa().length;i++){
	        	 pw.println(this.getCartasMesa()[i].toString());
	         }
	         
	         //Y ahora las estadisticas
	         pw.println("\n" + "ESTADISTICAS PAREJAS");
	         pw.println("PAREJA1: ");
	         pw.println("PUNTOS GANADOS PAREJA: " + this.getPareja(1).getEstadisticas().getPuntosPareja());
	         pw.println("VACAS GANADAS PAREJA: " + this.getPareja(1).getEstadisticas().getVacasPareja());
	         pw.println("PAREJA2: ");
	         pw.println("PUNTOS GANADOS PAREJA: " + this.getPareja(2).getEstadisticas().getPuntosPareja());
	         pw.println("VACAS GANADAS PAREJA: " + this.getPareja(2).getEstadisticas().getVacasPareja());
	         
	         
	         
	         pw.close();
		 }catch (Exception e){
			 e.printStackTrace();
		 }
	}
}
